package cn.tedu.csmall.passport.service.impl;

import cn.tedu.csmall.passport.ex.ServiceException;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.pojo.dto.AdminAddNewDTO;
import cn.tedu.csmall.passport.pojo.dto.AdminLoginInfoDTO;
import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.csmall.passport.repo.IAdminRedisRepository;
import cn.tedu.csmall.passport.security.AdminDetails;
import cn.tedu.csmall.passport.service.IAdminService;
import cn.tedu.csmall.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 处理管理员数据的业务实现类
 *
 * @author java@tedu.cn
 * @version 0.0.1
 */
@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    @Autowired
    AdminMapper adminMapper;
    @Autowired
    AdminRoleMapper adminRoleMapper;
    @Autowired
    AuthenticationManager authenticationManager;
    @Autowired
    IAdminRedisRepository repository;
    @Value("${csmall.jwt.secret-key}")
    private String secretKey;
 @Value("${csmall.jwt.duration-in-minute}")
    private Long durationInMinute;

    public AdminServiceImpl() {
        log.info("创建业务对象：AdminServiceImpl");
    }

    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        log.debug("开始处理【添加管理员】的业务，参数：{}", adminAddNewDTO);

        log.debug("即将检查用户名是否被占用……");
        {
            // 从参数对象中获取username
            String username = adminAddNewDTO.getUsername();
            // 调用adminMapper的countByUsername()方法执行统计查询
            int count = adminMapper.countByUsername(username);
            // 判断统计结果是否不等于0
            if (count != 0) {
                // 是：抛出异常
                String message = "添加管理员失败，用户名【" + username + "】已经被占用！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        log.debug("即将检查手机号码是否被占用……");
        {
            // 从参数对象中获取手机号码
            String phone = adminAddNewDTO.getPhone();
            // 调用adminMapper的countByPhone()方法执行统计查询
            int count = adminMapper.countByPhone(phone);
            // 判断统计结果是否不等于0
            if (count != 0) {
                // 是：抛出异常
                String message = "添加管理员失败，手机号码【" + phone + "】已经被占用！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        log.debug("即将检查电子邮箱是否被占用……");
        {
            // 从参数对象中获取电子邮箱
            String email = adminAddNewDTO.getEmail();
            // 调用adminMapper的countByEmail()方法执行统计查询
            int count = adminMapper.countByEmail(email);
            // 判断统计结果是否不等于0
            if (count != 0) {
                // 是：抛出异常
                String message = "添加管理员失败，电子邮箱【" + email + "】已经被占用！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        // 创建Admin对象
        Admin admin = new Admin();
        // 通过BeanUtils.copyProperties()方法将参数对象的各属性值复制到Admin对象中
        BeanUtils.copyProperties(adminAddNewDTO, admin);
        // TODO 取出密码，进行加密处理，并将密文封装回Admin对象中
        // 补全Admin对象中的属性值：loginCount >>> 0
        admin.setLoginCount(0);
        // 调用adminMapper的insert()方法插入数据
        log.debug("即将插入管理员数据，参数：{}", admin);
        int rows = adminMapper.insert(admin);
        // 判断插入数据的结果是否符合预期
        if (rows != 1) {
            String message = "添加管理员失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        // 开始插入管理员与角色关联的数据
        Long[] roleIds = adminAddNewDTO.getRoleIds();
        AdminRole[] adminRoles = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < roleIds.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            admin.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoles[i] = adminRole;
        }
        rows = adminRoleMapper.insertBatch(adminRoles);
        if (rows != roleIds.length) {
            String message = "添加管理员失败,服务器忙，请稍后再次尝试！";
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理【查询管理员列表】的业务，无参数");
        List<AdminListItemVO> list = adminMapper.list();
        Iterator<AdminListItemVO> iterator = list.iterator();
        while (iterator.hasNext()) {
            AdminListItemVO next = iterator.next();
            if (next.getId() == 1) {
                iterator.remove();
                break;
            }
        }
        return list;
    }

    @Override
    public void delete(Long id) {
        log.debug("开始处理【根据{}删除】对象的业务", id);
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null) {
            String message = "id为" + id + " 的对象不存在,不能删除!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        int count = adminMapper.deleteById(id);
        if (count != 1) {
            String message = "删除失败,服务器忙,请稍后再试....";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
        log.debug("删除成功!");
        // 删除与管理员关联的角色
        int rows = adminRoleMapper.deleteByAdminId(id);
        if (rows < 1) {
            String message = "删除失败,服务器忙,请稍后再试....";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
        log.debug("删除成功!");
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id, 1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id, 0);
    }


    @Override
    public String login(AdminLoginInfoDTO adminLoginInfoDTO) {
        log.debug("开始处理管理员登录的业务,参数:{}", adminLoginInfoDTO);
// authentication 认证信息
        Authentication authentication = new
                UsernamePasswordAuthenticationToken(adminLoginInfoDTO.getUsername(), adminLoginInfoDTO.getPassword());
        log.debug("调用认证管理器执行认证!!!");
        Authentication authenticateResult = authenticationManager.authenticate(authentication);
        //SecurityContextHolder.getContext().setAuthentication(authenticate);
        log.debug("认证通过,认证管理器返回对象:{}", authenticateResult);
        Object principal = authenticateResult.getPrincipal();
        log.debug("认证结果中的当事人:{}",principal.getClass().getName());
       AdminDetails adminDetails = (AdminDetails) principal;
        String username=adminDetails.getUsername();
        Long id = adminDetails.getId();
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();
        String s = JSON.toJSONString(authorities);
        //生成JWT数据时,需要填充到JWT中的数据
        Date date = new Date(System.currentTimeMillis() + durationInMinute* 60 * 1000L);
        Map<String, Object> claims = new HashMap();
        claims.put("id", id);
        log.debug("向JWT中存入id:{}",id);
        claims.put("username", username);
        claims.put("s",s);
        String jwt = Jwts.builder()
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                .setClaims(claims)
                .setExpiration(date)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
       log.debug("生成的JWT数据{}",jwt);
       return jwt;
    }


    public void updateEnableById(Long id, Integer enable) {
        String[] s = {"禁用", "启用"};
        if (id == 1) {
            String message = "" + s[enable] + "管理员失败,该管理员没被发现";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);

        }
        AdminStandardVO adminStandard = adminMapper.getStandardById(id);
        if (adminStandard == null) {
            String message = "" + s[enable] + "管理员失败,该对象不存在!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        if (adminStandard.getEnable() == enable) {
            String message = "" + s[enable] + "管理员失败,该对象已经被" + s[enable] + "!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);

        }
        Admin admin = new Admin();
        admin.setEnable(enable);
        admin.setId(id);
        int update = adminMapper.update(admin);
        if (update != 1) {
            String message = "修改【是否启用】失败,服务器忙,请稍后再试...";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }
    public void rebuildAdminCache(){
        repository.deleteAll();
        List<AdminListItemVO> list = adminMapper.list();
        repository.save(list);
        log.debug("准备将各管理员的详情写入Redis缓存...");
        for (AdminListItemVO item : list) {
            Long id = item.getId();
            AdminStandardVO standardById = adminMapper.getStandardById(id);
            repository.save(standardById);
        }
        log.debug("将各理员的详情写入到Redis缓存完成!");
    }

}
